#include	"TextFilter.h"

#include	<Logger.h>
#include	<cstdio>
#include	<cstring>

#if defined(_WIN32)
#	pragma	warning(disable:4996)
#endif

bool TextFilter::Initialize() {
	FILE * file = NULL;
	char buffer[512] = { 0 };

	if ((file = fopen("settings/filter/badwords.txt", "r")) == NULL) {
		LOG_ERR("Failed to open settings/filter/badwords.txt");
		return false;
	}

	std::string line, regex;
	line.reserve(512);
	regex.reserve(8192);

	while (!feof(file)) {
		memset(buffer, 0, 512);

		char * p = fgets(buffer, 512, file);
		if (!p) break;
		p++;

		line.clear();
		while (*p && *p != '\r' && *p != '\n') {
			line.push_back(*p);
			p++;
		}

		if (line.size() == 0) continue;

		size_t l = 0;
		uint32_t h = Char((char *)line.c_str(), l);

		if (*buffer == '=') {
			if (_badwords.find(h) == _badwords.end()) _badwords[h] = std::vector<std::string>();
			_badwords[h].push_back(line);
		} else if (*buffer == '@') {
			regex.append(line);
			regex.append("|");
		} else {
			continue;
		}
	}

	if (regex.size() > 0) {
		regex.pop_back();
#if USE_CPP_REGEX
		try {
			_regex = new std::regex(regex);
		} catch (...) {
			LOG_ERR("Failed to compile : %s", regex.c_str());
			return false;
		}
#else
		_regex = new regex_t;
		if (0 != regcomp(_regex, regex.c_str(), REG_EXTENDED)) {
			LOG_ERR("Failed to compile : %s", regex.c_str());
			delete _regex;
			_regex = nullptr;
			return false;
		}
#endif
	}

	return true;
}

bool TextFilter::Check(const std::string & words) {
	char * p = (char *)words.c_str();
	size_t n = words.size();

	for (size_t i = 0; i < n; ) {
		size_t l = 0;
		uint32_t c = Char(p + i, l);

		auto it = _badwords.find(c);
		if (it != _badwords.end()) {
			for (auto & s : it->second) {
				if (s.size() > n - i) continue;
				if (memcmp(s.c_str(), p + i, s.size()) == 0) return false;
			}
		}

		i += l;
	}

	if (_regex) {
#if USE_CPP_REGEX
		if (std::regex_match(words, *_regex)) return false;
#else
		if (regexec(_regex, words.c_str(), 0, NULL, 0) == 0) return false;
#endif
	}

	return true;
}

uint32_t TextFilter::Char(char * p, size_t & l) {
	uint8_t c = *(uint8_t *)p;

	if (c > 0xF0) {
		l = 4;
	} else if (c > 0xE0) {
		l = 3;
	} else if (c > 0xC0) {
		l = 2;
	} else {
		l = 1;
	}

	uint32_t n = 0;

	for (size_t i = 0; i < l; ++i) {
		if (!*(p + i)) return 0;
		n = (n << 8) | *(uint8_t *)(p + i);
	}

	return n;
}